package edu.stanford.bmir.protege.web.client.ui.ontology.stkos.common.treepanel;

import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDatatype;
import org.semanticweb.owlapi.model.OWLEntityVisitorEx;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;

import com.google.common.base.Optional;
import com.google.gwt.core.shared.GWT;
import com.google.web.bindery.event.shared.Event.Type;
import com.gwtext.client.widgets.tree.TreeNode;

import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager;
import edu.stanford.bmir.protege.web.client.project.Project;
import edu.stanford.bmir.protege.web.client.rpc.AbstractWebProtegeAsyncCallback;
import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.ui.library.msgbox.MessageBox;
import edu.stanford.bmir.protege.web.shared.DataFactory;
import edu.stanford.bmir.protege.web.shared.entity.OWLNamedIndividualData;
import edu.stanford.bmir.protege.web.shared.event.NamedIndividualFrameChangedEvent;
import edu.stanford.bmir.protege.web.shared.event.NamedIndividualFrameChangedEventHandler;
import edu.stanford.bmir.protege.web.shared.individualslist.GetIndividualsAction;
import edu.stanford.bmir.protege.web.shared.individualslist.GetIndividualsResult;
import edu.stanford.bmir.protege.web.shared.pagination.PageRequest;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

/**
 * Stkos Individual Tree Panel
 * 
 * @author LWS
 * 
 */
@SuppressWarnings("unchecked")
public class StkosIndividualTreePanel extends AbstractStkosTreePanel {

	public static final OWLEntityVisitorEx<String> CSS_CLASS_NAME_VISITOR = new OWLEntityVisitorEx<String>() {
		@Override
		public String visit(OWLClass cls) {
			return "stkosutil-class-icon-inset";
		}

		@Override
		public String visit(OWLObjectProperty property) {
			return "stkosutil-object-property-icon-inset";
		}

		@Override
		public String visit(OWLDataProperty property) {
			return "stkosutil-data-property-icon-inset";
		}

		@Override
		public String visit(OWLNamedIndividual individual) {
			return "stkosutil-individual-icon-inset";
		}

		@Override
		public String visit(OWLDatatype datatype) {
			return "stkosutil-datatype-icon-inset";
		}

		@Override
		public String visit(OWLAnnotationProperty property) {
			return "stkosutil-annotation-property-icon-inset";
		}
	};

	protected EntityData ownerCls;

	public StkosIndividualTreePanel(Project project, EntityData ownerCls) {
		super(project);
		this.ownerCls = ownerCls;
	}

	@Override
	protected TreeNode createRootNode() {
		if (ownerCls == null) {
			return super.createRootNode();
		}
		TreeNode treeNode = createTreeNode(ownerCls);
		treeNode.setLeaf(false);
		treeNode.setExpandable(true);
		return treeNode;
	}

	@Override
	protected void registerProjectEventHandler() {
	}
	
	protected void registerProjectEventHandler2222() {
		ProjectId projectId = getProject().getProjectId();
		Type<NamedIndividualFrameChangedEventHandler> type = NamedIndividualFrameChangedEvent.TYPE;
		NamedIndividualFrameChangedEventHandler handler = new NamedIndividualFrameChangedEventHandler() {
			@Override
			public void namedIndividualFrameChanged(
					NamedIndividualFrameChangedEvent event) {
				if (event == null || event.getEntity() == null
						|| event.getEntity().getIRI() == null) {
					return;
				}
				try {
					TreeNode node = (TreeNode) getNodeById(event.getEntity()
							.getIRI().toString());

					refreshTreeNode(node);
				} catch (Exception e) {
					GWT.log("Update tree node text error.", e);
				}
			}
		};

		manager.registerHandlerToProject(projectId, type, handler);
	}

	@Override
	protected void setRootNodeChild() {
		ProjectId projectId = getProject().getProjectId();
		Optional<OWLClass> otype = toOWLClass(ownerCls);
		if (!otype.isPresent()) {
			return;
		}
		OWLClass type = otype.get();
		Optional<PageRequest> pageRequest = Optional.<PageRequest> absent();
		GetIndividualsAction action = new GetIndividualsAction(projectId, type,
				pageRequest);
		AbstractWebProtegeAsyncCallback<GetIndividualsResult> cb = new AbstractWebProtegeAsyncCallback<GetIndividualsResult>() {
			@Override
			public void onSuccess(GetIndividualsResult result) {
				if (result == null || result.getIndividuals() == null
						|| result.getIndividuals().size() == 0) {
					GWT.log("Class [" + ownerCls + "] has no individuals.");
					return;
				}

				for (OWLNamedIndividualData oid : result.getIndividuals()) {
					TreeNode treeNode = createTreeNode(oid);
					if (treeNode != null) {
						getRootNode().appendChild(treeNode);
					}
				}
			}
		};
		DispatchServiceManager.get().execute(action, cb);
	}

	protected TreeNode createTreeNode(OWLNamedIndividualData owlEntityData) {
		if (owlEntityData == null) {
			return null;
		}
		TreeNode treeNode = new TreeNode(owlEntityData.getBrowserText());
		treeNode.setId(owlEntityData.getEntity().getIRI().toString());
		treeNode.setIconCls(owlEntityData.accept(CSS_CLASS_NAME_VISITOR,
				"stkosutil-empty-icon-inset"));
		treeNode.setTooltip(owlEntityData.getEntity().getIRI().toString());
		treeNode.setLeaf(true);
		treeNode.setExpandable(false);
		treeNode.setUserObject(owlEntityData);
		return treeNode;
	}

	@Override
	protected void getChildren(TreeNode node) {
		if (node == null || node.getId() == null) {
			return;
		}
		if (node.getChildNodes() != null && node.getChildNodes().length > 0) {
			return;
		}
		if (ROOTNODEID.equals(node.getId())) {
			onRefresh();
			return;
		}
		if (ownerCls != null && node.getId().equals(ownerCls.getName())) {
			onRefresh();
			return;
		}
		MessageBox.showAlert("No method to find individual childrens.");
	}

	protected Optional<OWLClass> toOWLClass(EntityData entityData) {
		if (entityData == null) {
			return Optional.absent();
		}
		String name = entityData.getName();
		if (name == null) {
			return Optional.absent();
		}
		return Optional.of(DataFactory.getOWLClass(name));
	}

	public void setOwnerCls(EntityData ownerCls) {
		this.ownerCls = ownerCls;
		TreeNode root = createRootNode();
		getRootNode().setId(root.getId());
		getRootNode().setText(root.getText());
		getRootNode().setUserObject(root.getUserObject());

		onRefresh();
	}

	public EntityData getOwnerCls() {
		return this.ownerCls;
	}
}
